package listeners

import (
	"blockchains-aio/conf"
	"blockchains-aio/db"
	"blockchains-aio/stack"
	"blockchains-aio/util"
	"fmt"
	"github.com/gin-gonic/gin"
	"log"
	"net/http"
	"os"
)

func RegisterExplorer(router *gin.Engine) {
	router.MaxMultipartMemory = 8 << 10 // 8 KB

	explorer := router.Group("/explorer")
	{
		// eth explorer
		explorer.POST("/eth/tmpl", doGenEthExplorerConfig)
		explorer.POST("/eth", doDeployForEthExplorer)

		// lite explorer for pos
		explorer.POST("/pos/tmpl", doGenLiteExplorerConfig)
		explorer.POST("/pos", doDeployForLiteExplorer)
	}

}

func doGenLiteExplorerConfig(ctx *gin.Context) {
	var liteExplorerConfig stack.LiteExplorer
	consensus := ctx.GetHeader("Consensus-Template-Type") //lite_explorer

	if err := ctx.BindJSON(&liteExplorerConfig); err != nil {
		ctx.JSON(http.StatusBadRequest, err)
		return
	}

	liteExplorerTmpl := fmt.Sprintf("%s/%s.tmpl", conf.GetStackTemplateFolder(), consensus)
	err := stack.ParseLiteExplorerTemplate(ctx.Writer, liteExplorerTmpl, liteExplorerConfig)
	if err != nil {
		ctx.JSON(http.StatusBadRequest, fmt.Sprintf("%v", err))
	}
}

func doDeployForLiteExplorer(ctx *gin.Context) {

	chainname := ctx.PostForm("chainname")
	consensus := ctx.PostForm("consensus") //lite_explorer
	extra := ctx.PostForm("extra")

	log.Printf("recieved {chainname:%s,consensus:%s}", chainname, consensus)

	file, _ := ctx.FormFile("file")
	f, err := file.Open()
	if err != nil {
		//ctx.JSON(400, fmt.Sprintf("Failed to open yaml:%v", err))
		ctx.JSON(400, NewErrorMessage(Stack, 1, "doDeployForLiteExplorer", fmt.Sprintf("Failed to open yaml:%v", err)).Json())
		return
	}
	defer f.Close()

	p := make([]byte, file.Size)
	if _, err := f.Read(p); err != nil {
		//ctx.JSON(400, fmt.Sprintf("Failed to read yaml: %v", err))
		ctx.JSON(400, NewErrorMessage(Stack, 2, "doDeployForLiteExplorer", fmt.Sprintf("Failed to read yaml:%v", err)).Json())
		return
	}

	chainFolder := fmt.Sprintf("%s/%s", conf.GetNfsFolder(), chainname)
	if err := util.CreateAllDir(chainFolder); err != nil {
		//ctx.JSON(400, fmt.Sprintf("Fail to create chain dir: %v", err))
		ctx.JSON(400, NewErrorMessage(Stack, 3, "doDeployForLiteExplorer", fmt.Sprintf("Fail to create chain dir: %v", err)).Json())
		return
	}
	//yaml := chainFolder + "/" + chainname + ".yml"
	yaml := chainFolder + "/" + conf.DefaultComposeFileName

	if err := os.WriteFile(yaml, p, 0644); err != nil {
		//ctx.JSON(400, fmt.Sprintf("Failed to write file %s: %v", yaml, err))
		ctx.JSON(400, NewErrorMessage(Stack, 4, "doDeployForLiteExplorer", fmt.Sprintf("Failed to write file %s: %v", yaml, err)).Json())
		return
	}

	log.Printf(fmt.Sprintf("working directory: %s", chainFolder))
	out, err := util.DockerComposeDeployUpConfigFile(yaml, chainFolder)
	if err != nil {
		//ctx.JSON(400, fmt.Sprintf("Failed to deploy stack: %v", err))
		ctx.JSON(400, NewErrorMessage(Stack, 5, "doDeployForLiteExplorer", fmt.Sprintf("Failed to deploy stack: %v", err)).Json())
		return
	}

	if err = db.CreateStack2(chainname, consensus, string(p), extra, 1); err != nil {
		//ctx.JSON(http.StatusBadRequest, fmt.Sprintf("Failed to store the stack{chainname:%s, consensus:%s, config:%s, nodeNumber:%v}: %v", chainname, consensus, string(p), 1, err))
		ctx.JSON(http.StatusBadRequest, NewErrorMessage(Stack, 6, "doDeployForLiteExplorer", fmt.Sprintf("Failed to store the stack{chainname:%s, consensus:%s, config:%s, nodeNumber:%v}: %v", chainname, consensus, string(p), 1, err)).Json())
		return
	}

	ctx.JSON(200, string(out))
}

func doGenEthExplorerConfig(ctx *gin.Context) {
	var ethExplorerConfig stack.EthExplorer
	consensus := ctx.GetHeader("Consensus-Template-Type") //eth_explorer

	if err := ctx.BindJSON(&ethExplorerConfig); err != nil {
		ctx.JSON(http.StatusBadRequest, err)
		return
	}

	ethExplorerTmpl := fmt.Sprintf("%s/%s.tmpl", conf.GetStackTemplateFolder(), consensus)
	err := stack.ParseEthExplorerTemplate(ctx.Writer, ethExplorerTmpl, ethExplorerConfig)
	if err != nil {
		ctx.JSON(http.StatusBadRequest, fmt.Sprintf("%v", err))
	}
}

func doDeployForEthExplorer(ctx *gin.Context) {

	chainname := ctx.PostForm("chainname")
	consensus := ctx.PostForm("consensus")
	extra := ctx.PostForm("extra")

	log.Printf("recieved {chainname:%s,consensus:%s}", chainname, consensus)

	file, _ := ctx.FormFile("file")
	f, err := file.Open()
	if err != nil {
		ctx.JSON(400, fmt.Sprintf("Failed to open yaml:%v", err))
		return
	}
	defer f.Close()

	p := make([]byte, file.Size)
	if _, err := f.Read(p); err != nil {
		ctx.JSON(400, fmt.Sprintf("Failed to read yaml: %v", err))
		return
	}

	chainFolder := fmt.Sprintf("%s/%s", conf.GetNfsFolder(), chainname)
	if err := util.CreateAllDir(chainFolder); err != nil {
		ctx.JSON(400, fmt.Sprintf("Fail to create chain dir: %v", err))
		return
	}
	//yaml := chainFolder + "/" + chainname + ".yml"
	yaml := chainFolder + "/" + conf.DefaultComposeFileName

	if err := os.WriteFile(yaml, p, 0644); err != nil {
		ctx.JSON(400, fmt.Sprintf("Failed to write file %s: %v", yaml, err))
		return
	}

	log.Printf(fmt.Sprintf("working directory: %s", chainFolder))
	out, err := util.DockerComposeDeployUpConfigFile(yaml, chainFolder)
	if err != nil {
		ctx.JSON(400, fmt.Sprintf("Failed to deploy stack: %v", err))
		return
	}

	if err = db.CreateStack2(chainname, consensus, string(p), extra, 1); err != nil {
		ctx.JSON(http.StatusBadRequest, fmt.Sprintf("Failed to store the stack{chainname:%s, consensus:%s, config:%s, nodeNumber:%v}: %v", chainname, consensus, string(p), 1, err))
		return
	}

	ctx.JSON(200, string(out))
}
